#ifndef A8_UDPLOG_HPP
#define A8_UDPLOG_HPP

#include <a8/sync.hpp>
#include <a8/thread.hpp>

namespace a8
{
	class UdpLog
	{
	public:
		unsigned short  mLogLevel;
		bool mDebuging;
		std::string mLogFileName;
	public:
		UdpLog()
		{
			mLogLevel = 0;
			mDebuging = false;
			mTopNode = NULL;
			mBotNode = NULL;
			mWorkNode = NULL;
			mSaveThread.OnExecute += std::make_pair(this, &UdpLog::SaveToFileThreadProc);
		}

		~UdpLog()
		{
		}

		void Init()
		{
			mSaveThread.Start();
		}

		void UnInit()
		{
		}

		void Emergency(const char *format)
		{
			if(mLogLevel > 6){
				return;
			}
			SendLog("[EMERGENCY]", format, NULL, 0);
		}

		void Alert(const char *format)
		{
			if(mLogLevel > 5){
				return;
			}
			SendLog("[ALERT]", format, NULL, 0);
		}

		void Error(const char *format)
		{
			if(mLogLevel > 4){
				return;
			}
			SendLog("[ERROR]", format, NULL, 0);
		}

		void Warning(const char *format)
		{
			if(mLogLevel > 3){
				return;
			}
			SendLog("[WARNING]", format, NULL, 0);
		}

		void Notice(const char *format)
		{
			if(mLogLevel > 2){
				return;
			}
			SendLog("[NOTICE]", format, NULL, 0);
		}

		void Info(const char *format)
		{
			if(mLogLevel > 1){
				return;
			}
			SendLog("[INFO]", format, NULL, 0);
		}

		void Debug(const char *format)
		{
			if(mLogLevel > 0){
				return;
			}
			SendLog("[DEBUG]", format, NULL, 0);
		}

	private:
		struct LogMsgNode
		{
			std::string logmsg;
			LogMsgNode* nextnode;

			LogMsgNode():nextnode(NULL)
			{
			}
		};

	private:
		a8::Runnable mSaveThread;

		a8::sync::Mutex mMsgMutex;
		LogMsgNode *mTopNode, *mBotNode, *mWorkNode;

	private:
		void SendLog(const char *category, const char *format, a8::XValue* args, int argnum)
		{
			time_t nowtime = time(NULL);
			struct tm tm_nowtime = {0};
			struct tm *ptr = localtime_r(&nowtime, &tm_nowtime);
			char strtime[80];
			strftime(strtime, 80, "%F %T", ptr);

			LogMsgNode *p = new LogMsgNode();
			p->logmsg.reserve(128);
			p->logmsg.append((char*)strtime);
			p->logmsg.append(category);
			p->logmsg.append(" ");
			p->logmsg.append(a8::format(format, args, argnum));
			p->logmsg.append("\n");
			if(mDebuging){
				printf("%s", p->logmsg.c_str());
			}
			mMsgMutex.Lock();
			if(mBotNode){
				mBotNode->nextnode = p;
				mBotNode = p;
			}else{
				mTopNode = p;
				mBotNode = p;
			}
			mMsgMutex.UnLock();
	    }

		void SaveToFileThreadProc(a8::Runnable *thread)
		{
			while (!thread->IsShutdown()){
				if(!mWorkNode && mTopNode){
					mMsgMutex.Lock();
					mWorkNode = mTopNode;
					mTopNode = NULL;
					mBotNode = NULL;
					mMsgMutex.UnLock();
				}

				if(mWorkNode){
					time_t nowtime = time(NULL);
					struct tm tm_nowtime = {0};
					localtime_r(&nowtime, &tm_nowtime);

					char szfilename[120];
					strftime(szfilename, 120, mLogFileName.c_str(), &tm_nowtime);
					std::string filename((char*)szfilename);
					FILE *logfile = fopen(filename.c_str(), "a+");  
					if(logfile){
						while (mWorkNode){
							LogMsgNode *nextnode = mWorkNode->nextnode;
							fwrite(mWorkNode->logmsg.c_str(), 1, mWorkNode->logmsg.length(), logfile);  
							delete mWorkNode;
							mWorkNode = nextnode;
						}
						fclose(logfile);
					}
				}
				usleep(10000 * 100 * 10);
			}
		}
	public:
#include <a8/inc/udplog.inl>
	};
}

#endif
